package nokia.iap.ui.lib.prodcatalog;


import com.nokia.mid.payment.IAPClientPaymentException;
import com.nokia.mid.payment.IAPClientPaymentListener;
import com.nokia.mid.payment.IAPClientPaymentManager;
import com.nokia.mid.payment.IAPClientProductData;
import com.nokia.mid.payment.IAPClientUserAndDeviceData;
import java.util.Vector;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemCommandListener;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.Spacer;
import javax.microedition.lcdui.StringItem;
import javax.microedition.midlet.MIDlet;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author zinin
 */
public class ProductCatalogForm extends Form 
                        implements IAPClientPaymentListener, CommandListener, ItemStateListener{
    //constants section
    private final int INVALID_INDEX = -1;
    public static final String DRM_PATH = "drm/data/resourceid_";

    //string prompts text
    private static final String KBuyStr = "Buy";
    private static final String KOkStr = "Ok";
    private static final String KCancelStr = "Cancel";
    private static final String KBuyConfimTitleStr = "Purchasing";
    private static final String KBuyConfimStr = "You are about to buy the product. Continue?";
    private static final String KViewContentStr = "Unlocked content";
    private static final String KItemsTobuyTitleStr = "Items to buy";
    private static final String KItemsYouHaveTitleStr = "Items you have";
    private static final String KPleaseWaitStr = "please wait";
    
    private static final Command buyCommand =  new Command(KBuyStr, Command.ITEM, 0);
    private static final Command viewCommand =  new Command(KViewContentStr, Command.ITEM, 0);
    private static final Command okConfirmCommand = new Command(KOkStr, Command.OK, 1);
    private static final Command cancelConfirmCommand = new Command(KCancelStr, Command.CANCEL, 1);
            
    private ChoiceGroup itemsTobuyGroup;
    private StringItem buyButton;
    private final Gauge gauge = new Gauge(KPleaseWaitStr, false, Gauge.INDEFINITE, Gauge.CONTINUOUS_RUNNING);
    private final Spacer spacer = new Spacer(15, 1);
    private final ChoiceGroup itemsYouHaveGroup = new ChoiceGroup(KItemsYouHaveTitleStr, Choice.MULTIPLE);
    private int SPINNER_PLACE = 1;
    
    private final String[] productList;
    private IAPClientPaymentManager iapClient = null;
    boolean isBusy;
    
    private final ProductCatalogListener client;

    private Alert confirmDialog;
    
    private boolean isTouchDevice;
    
    private final BasicRMS rms = new BasicRMS();
    private final int KSeparator = '|';
    
    private class IAPClientProductDataState{
        public String productId;
        public String title;
        public String shortDescription;
        public String longDescription;
        public String price;
        public int drmProtection;
        public int errorState = IAPClientPaymentListener.OK;
        public String ticket;       // NOTE cannot use empty ticket checking as "isUnlocked" mark 
                                    // because on emulator it cam be empty after successfull purchasing
        public boolean isUnlocked;
        public int listIndex;
    }
    private IAPClientProductDataState[] productDataList;
    
    private class UnlockedItemIndex{
        public int groupIndex;
        public int prodListIndex;
        
        public UnlockedItemIndex(){
            groupIndex = INVALID_INDEX;
            prodListIndex = INVALID_INDEX;
        }
        
        public UnlockedItemIndex(int idxA, int idxB){
            groupIndex = idxA;
            prodListIndex = idxB;
        }
    }
    private UnlockedItemIndex[] boughtItemList;
    private int indexPurchasing = INVALID_INDEX;

    public ProductCatalogForm(final ProductCatalogListener client, String title, String[] productIds){
        super(title);
        
        try{
            Class.forName("com.nokia.mid.ui.gestures.GestureRegistrationManager");
            // This is a touch device
            isTouchDevice = true;
        }catch (Throwable e){
        }
        itemsTobuyGroup = new ChoiceGroup(KItemsTobuyTitleStr, isTouchDevice ? Choice.EXCLUSIVE : Choice.MULTIPLE);
        append(itemsTobuyGroup);
        createBuyButton();
        append(spacer);
        append(itemsYouHaveGroup);
        productList = productIds;
        itemsTobuyGroup.addCommand(buyCommand);
        itemsYouHaveGroup.addCommand(viewCommand);
        setCommandListener(this);
        setItemStateListener(this);
        this.client = client;
        
        //init confirmation dialog
        confirmDialog = new Alert(KBuyConfimTitleStr);
        confirmDialog.setString(KBuyConfimStr);
        confirmDialog.setCommandListener(this);
        confirmDialog.addCommand(okConfirmCommand);
        confirmDialog.addCommand(cancelConfirmCommand);
        confirmDialog.setType(AlertType.CONFIRMATION);
    }
    
    public void rebuildCatalog() throws IAPClientPaymentException{
        if(iapClient == null){
            iapClient = IAPClientPaymentManager.getIAPClientPaymentManager();
            IAPClientPaymentManager.setIAPClientPaymentListener(this);
        }
        int errcode = iapClient.getProductData(productList);
        if(errcode != IAPClientPaymentManager.SUCCESS){
            throw new IAPClientPaymentException("getProductData failed with : " + errcode);
        }
        setBusy();
    }
    
    public void productDataReceived(int status, IAPClientProductData pd) {
        //not used
    }

    public void productDataListReceived(int status, IAPClientProductData[] list) {
        setReady();
        productDataList = new IAPClientProductDataState[list.length];
        boughtItemList = new UnlockedItemIndex[list.length];

        for(int i = 0; i < productDataList.length; i++){
            productDataList[i] = new IAPClientProductDataState();
            productDataList[i].productId = list[i].getProductId();
            productDataList[i].title = list[i].getTitle();
            productDataList[i].shortDescription = list[i].getShortDescription();
            productDataList[i].longDescription = list[i].getLongDescription();
            productDataList[i].price = list[i].getPrice();
            productDataList[i].drmProtection = list[i].getDrmProtection();
            productDataList[i].listIndex = i;
            boughtItemList[i] = new UnlockedItemIndex();
        }

        deSerialiseProduct(productDataList);

        for(int i = 0; i < productDataList.length; i++){
            if(!productDataList[i].isUnlocked){
                itemsTobuyGroup.append(productDataList[i].shortDescription + ", price: " + productDataList[i].price, null);
            }
        }
        
        itemsTobuyGroup.setFitPolicy(Choice.TEXT_WRAP_ON);
        if(!isTouchDevice){
            itemsTobuyGroup.setSelectedFlags(new boolean[productDataList.length]);
        }
        
        updateTitle();
    }

    public void purchaseCompleted(int status, String purchaseTicket) {
        setReady();
        
        if(status != IAPClientPaymentListener.OK && status != IAPClientPaymentListener.RESTORABLE) {
            return;
        }
        
        IAPClientProductDataState product = getItemTobuyByIndex(indexPurchasing);
        product.errorState = status;
        product.ticket = purchaseTicket;
        product.isUnlocked = true;
        
        itemsYouHaveGroup.append(product.longDescription + " unlocked", null);
        itemsTobuyGroup.delete(indexPurchasing);
        indexPurchasing = INVALID_INDEX;
        
        appendUnlockedItem(new UnlockedItemIndex(itemsYouHaveGroup.size() - 1, product.listIndex));
     
        updateTitle();
		
        serialiseProduct(product.productId);
    }
	
    private void serialiseProduct(String productId){
        rms.open();
        rms.set(productId.getBytes());
        rms.close();
    }

    private void deSerialiseProduct(IAPClientProductDataState[] list){
        rms.open();
        Vector productArray = rms.get();
        if(!productArray.isEmpty()){
            for(int i=0; i < list.length; i++){
                IAPClientProductDataState product = list[i];
                if(productArray.contains(product.productId)){
                    product.errorState = IAPClientPaymentListener.OK;
                    product.ticket = "from RMS";
                    product.isUnlocked = true;
                    itemsYouHaveGroup.append(product.longDescription + " unlocked", null);
                    appendUnlockedItem(new UnlockedItemIndex(itemsYouHaveGroup.size() - 1, product.listIndex));
                }
            }
        }
        rms.close();
    }

    public void restorationCompleted(int status, String purchaseTicket) {
        //not used
    }

    public void restorableProductsReceived(int status, IAPClientProductData[] productDataList) {
        //not used
    }

    public void userAndDeviceDataReceived(int status, IAPClientUserAndDeviceData ud) {
        //not used
    }

    public void commandAction(Command c, Displayable d) {
        if (c == buyCommand) {
            client.getDisplay().setCurrent(confirmDialog,this);
        } else if (c == viewCommand) {
            viewCommandAction();
        } else if (c == okConfirmCommand) {
            client.getDisplay().setCurrent(this);
            buyCommandAction();
        } else if (c == cancelConfirmCommand) {
            if(!isTouchDevice){
                //clean the selection
                itemsTobuyGroup.setSelectedFlags(new boolean[itemsTobuyGroup.size()]); 
            }
            client.getDisplay().setCurrent(this);
        }
    }

    private void setBusy() {
        if(isTouchDevice){
            delete(SPINNER_PLACE);
        }
        insert(SPINNER_PLACE, gauge);
        isBusy = true;
    }
    
    private void setReady() {
        delete(SPINNER_PLACE);
        if(isTouchDevice){
            insert(SPINNER_PLACE, buyButton);
        }
        isBusy = false;
    }

    public void itemStateChanged(Item item) {
        if(isBusy == true) {
            return;
        }
        
        if(item !=null && item.equals(itemsTobuyGroup) && !isTouchDevice){
            client.getDisplay().setCurrent(confirmDialog,this);
        }if(item !=null && item.equals(itemsYouHaveGroup)){
            viewCommandAction();
        }
    }
    
    private IAPClientProductDataState getItemTobuyByIndex(int index){
        IAPClientProductDataState result;
        for(int i = 0, sought = index; i < productDataList.length; i++){
            result = productDataList[i];
            if(!result.isUnlocked) {
                sought--;
            }
                        
            if(sought == -1){
                return result;
            }
        }
        return null;
    }

    private void appendUnlockedItem(UnlockedItemIndex boughtItemIndex) {
        for(int i = 0; i < boughtItemList.length; i++){
            if(boughtItemList[i].groupIndex == INVALID_INDEX){
                boughtItemList[i] = boughtItemIndex;
                break;
            }
        }
    }

    private IAPClientProductDataState getUnlockedItem(int groupIndex) {
        for(int i = 0; i < boughtItemList.length; i++){
            if(boughtItemList[i].groupIndex == groupIndex){
                return productDataList[boughtItemList[i].prodListIndex];
            }
        }
        return null;
    }

    private int getSelectedIndexInGroup(ChoiceGroup itemsGroup) {
        boolean[] selectedIndexes = new boolean[itemsGroup.size()]; 
        itemsGroup.getSelectedFlags(selectedIndexes);
        for(int i = 0; i < selectedIndexes.length; i++){
            if(selectedIndexes[i]){
                return i;
            }
        }
        return INVALID_INDEX;
    }

    private void buyCommandAction() {
        if(isTouchDevice){
            indexPurchasing = itemsTobuyGroup.getSelectedIndex();
        }else{
            indexPurchasing = getSelectedIndexInGroup(itemsTobuyGroup);
            //clean the selection
            itemsTobuyGroup.setSelectedFlags(new boolean[itemsTobuyGroup.size()]); 
        }
        int errcode = iapClient.purchaseProduct(getItemTobuyByIndex(indexPurchasing).productId, 
                                    IAPClientPaymentManager.FORCED_AUTOMATIC_RESTORATION);

        if(errcode == IAPClientPaymentManager.SUCCESS){
            setBusy();
        }else{
            indexPurchasing = INVALID_INDEX;
            //TODO: pop-up error
        }
    }

    private void viewCommandAction() {
        int idx = getSelectedIndexInGroup(itemsYouHaveGroup);
        //clean the selection
        itemsYouHaveGroup.setSelectedFlags(new boolean[itemsYouHaveGroup.size()]); 
        IAPClientProductDataState product = getUnlockedItem(idx);
        client.useUnlockedProduct(product.productId);
    }

    private void updateTitle() {
        itemsYouHaveGroup.setLabel(this.KItemsYouHaveTitleStr + " (" + itemsYouHaveGroup.size() + ")");
        itemsTobuyGroup.setLabel(KItemsTobuyTitleStr + " (" + itemsTobuyGroup.size() + ")");
    }

    private void createBuyButton() {
        if(!isTouchDevice){
            return;
        }
        buyButton = new StringItem(null, KBuyStr, Item.BUTTON);
        buyButton.setDefaultCommand(buyCommand);
        buyButton.setItemCommandListener(new ItemCommandListener() {
            public void commandAction(Command c, Item item) {
                client.getDisplay().setCurrent(confirmDialog);
            }
        });
        insert(SPINNER_PLACE, buyButton);
    }
}
